using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WHLRDF.ORM
{
	/// <summary>
	/// The base class for an <see cref="ICriterion"/> that compares a single Property
	/// to a value.
	/// </summary>
	[Serializable]
	public class SimpleExpression : AbstractCriterion
	{
		private readonly IProjection _projection;
		private readonly string propertyName;
        private readonly string[] lstProperty;
        private readonly object value;
		private bool ignoreCase;
		private readonly string op;

		protected internal SimpleExpression(IProjection projection, object value, string op)
		{
			_projection = projection;
			this.value = value;
			this.op = op;
		}

		/// <summary>
		/// Initialize a new instance of the <see cref="SimpleExpression" /> class for a named
		/// Property and its value.
		/// </summary>
		/// <param name="propertyName">The name of the Property in the class.</param>
		/// <param name="value">The value for the Property.</param>
		/// <param name="op">The SQL operation.</param>
		public SimpleExpression(string propertyName, object value, string op)
		{
			this.propertyName = propertyName;
			this.value = value;
			this.op = op;
		}
        public SimpleExpression(string[] propertyName, object value, string op)
        {
            this.lstProperty = propertyName;
            this.value = value;
            this.op = op;
        }

        public SimpleExpression(string propertyName, object value, string op, bool ignoreCase)
			: this(propertyName, value, op)
		{
			this.ignoreCase = ignoreCase;
		}

		public SimpleExpression IgnoreCase()
		{
			ignoreCase = true;
			return this;
		}

		/// <summary>
		/// Gets the named Property for the Expression.
		/// </summary>
		/// <value>A string that is the name of the Property.</value>
		public string PropertyName
		{
			get { return propertyName; }
		}

		/// <summary>
		/// Gets the Value for the Expression.
		/// </summary>
		/// <value>An object that is the value for the Expression.</value>
		public object Value
		{
			get { return value; }
		}

		/// <summary>
		/// Converts the SimpleExpression to a <see cref="SqlString"/>.
		/// </summary>
		/// <returns>A SqlString that contains a valid Sql fragment.</returns>
		public override SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery)
		{
            return new SqlString();
			//SqlString[] columnNames =
			//	CriterionUtil.GetColumnNamesForSimpleExpression(
			//		propertyName,
			//		_projection,
			//		criteriaQuery,
			//		criteria,
			//		this,
			//		value);

			//TypedValue typedValue = GetParameterTypedValue(criteria, criteriaQuery);
			//Parameter[] parameters = criteriaQuery.NewQueryParameter(typedValue).ToArray();
   
			//if (ignoreCase)
			//{
			//	if (columnNames.Length != 1)
			//	{
			//		throw new HibernateException(
			//			"case insensitive expression may only be applied to single-column properties: " +
			//			propertyName);
			//	}
   
			//	return new SqlString(
			//		criteriaQuery.Factory.Dialect.LowercaseFunction,
			//		StringHelper.OpenParen,
			//		columnNames[0],
			//		StringHelper.ClosedParen,
			//		Op,
			//		parameters.Single());
			//}
			//else
			//{
			//	SqlStringBuilder sqlBuilder = new SqlStringBuilder(4 * columnNames.Length);
			//	var columnNullness = typedValue.Type.ToColumnNullness(typedValue.Value, criteriaQuery.Factory);

			//	if (columnNullness.Length != columnNames.Length)
			//	{
			//		throw new AssertionFailure("Column nullness length doesn't match number of columns.");
			//	}
   
			//	for (int i = 0; i < columnNames.Length; i++)
			//	{
			//		if (i > 0)
			//		{
			//			sqlBuilder.Add(" and ");
			//		}
   
			//		if (columnNullness[i])
			//		{
			//			sqlBuilder.Add(columnNames[i])
			//					  .Add(Op)
			//					  .Add(parameters[i]);
			//		}
			//		else
			//		{
			//			sqlBuilder.Add(columnNames[i])
			//					  .Add(" is null ");
			//		}
			//	}
			//	return sqlBuilder.ToSqlString();
			//}
		}

		
		public override IProjection[] GetProjections()
		{
			if (_projection != null)
			{
				return new IProjection[] { _projection };
			}
			return null;
		}

		public override string ToString()
		{
			return (_projection ?? (object)propertyName) + Op + ValueToStrings();
		}
        public override string ToString(ref DataParameterCollection dataParam, bool isNameParams = false)
        {
            if (this.lstProperty == null || this.lstProperty.Length <= 0)
            {
                if (string.IsNullOrWhiteSpace(propertyName))
                {
                    return " ";
                }
                string propertyName1 = propertyName;
               
                dataParam.Add(new DataParameter(propertyName1, value), ref propertyName1);
                return " " + propertyName + Op + (Op.ToLower().Trim().Equals("like") ? dataParam.GetLikeParameter(propertyName1) : dataParam.GetParameter(propertyName1) + " ") ;
            }
            else
            {
                StringBuilder strsql = new StringBuilder();
                strsql.Append(" ( ");
                int index = 0;
                foreach (var fieldName in this.lstProperty)
                {
                    string propertyName1 = fieldName;
                    dataParam.Add(new DataParameter(propertyName1, value), ref propertyName1);
                    if (index > 0)
                    {
                        strsql.Append(" or ");
                    }
                    strsql.Append(" " + fieldName + Op + (Op.ToLower().Trim().Equals("like") ?  dataParam.GetLikeParameter(propertyName1): dataParam.GetParameter(propertyName1) + " ") );
                    index++;
                }
                strsql.Append(" ) ");
                return strsql.ToString();
            }
        
        }
        /// <summary>
        /// Get the Sql operator to use for the specific 
        /// subclass of <see cref="SimpleExpression"/>.
        /// </summary>
        protected virtual string Op
		{
			get { return op; }
		}

		private static readonly System.Type[] CallToStringTypes = new[]
		{
			typeof(DateTime),
			typeof(string),
		};

        private string ValueToStrings()
        {
            if (value == null)
            {
                return "null";
            }
            var type = value.GetType();
            if (type.IsPrimitive || CallToStringTypes.Any(t => t.IsAssignableFrom(type)))
            {
                return value.ToString();
            }

            return value.ToString();
        }
    }
}
